
#pragma once

namespace atr {

/**
 * @brief Namespace only for internal use of atr library
 * @details Please don't use this namespace outside the atr library. IF you REALLY need to - do it with special care.
 */
namespace __ {

template <class Prevs, class Nexts,
          class Others,
          template <class, class> class Comparator,
          bool isGood>
    struct __merge;

template <template <class ...> class Base,
          class ... Prevs, class Current,
          class ... Others,
          template <class, class> class Comparator>
struct __merge<Base<Prevs...>, Base<Current>,
               Base<Others...>,
               Comparator,
               true>
    { using type = Base<Prevs..., Current, Others...>; };

template <template <class ...> class Base,
          class ... Prevs, class ... Nexts,
          class Current,
          template <class, class> class Comparator>
struct __merge<Base<Prevs...>, Base<Nexts...>,
               Base<Current>,
               Comparator,
               false>
    { using type = Base<Prevs..., Current, Nexts...>; };

template <template <class ...> class Base,
          class ... Prevs, class First, class Second, class ... Nexts,
          class Current, class ... Others,
          template <class, class> class Comparator>
struct __merge<Base<Prevs...>, Base<First, Second, Nexts...>,
               Base<Current, Others...>,
               Comparator,
               true>
    : public __merge<Base<Prevs..., First>, Base<Second, Nexts...>,
                     Base<Current, Others...>,
                     Comparator,
                     Comparator<Second, Current>::type::value> {};

template <template <class ...> class Base,
          class ... Prevs, class Current, class ... Nexts,
          class First, class Second, class ... Others,
          template <class, class> class Comparator>
struct __merge<Base<Prevs...>, Base<Current, Nexts...>,
               Base<First, Second, Others...>,
               Comparator,
               false>
    : public __merge<Base<Prevs..., First>, Base<Current, Nexts...>,
                     Base<Second, Others...>,
                     Comparator,
                     Comparator<Current, Second>::type::value> {};

template <template <class ...> class Base,
          class ... Nexts,
          template <class, class> class Comparator>
struct __merge<Base<>, Base<Nexts...>,
               Base<>,
               Comparator,
               true>
    { using type = Base<Nexts...>; };

template <template <class ...> class Base,
          class ... Others,
          template <class, class> class Comparator>
struct __merge<Base<>, Base<>,
               Base<Others...>,
               Comparator,
               true>
    { using type = Base<Others...>; };

template <template <class ...> class Base,
          template <class, class> class Comparator>
struct __merge<Base<>, Base<bool>,
               Base<>,
               Comparator,
               true>
    { using type = Base<bool>; };

} // namespace __
} // namespace atr
